// bboard.c

#include <ansi.h>

#define BOARD_CAPACITY query("capacity")

inherit ITEM;
inherit F_SAVE;

void setup()
{
    string loc;

    if (stringp(loc = query("location")))
        move(loc);
    set("no_get", 1);
    restore();
}

void init()
{
    add_action("do_post", "post");
    add_action("do_read", "read");
    add_action("do_discard", "discard");
}

string query_save_file()
{
    string id;

    if (!stringp(id = query("board_id")))
        return 0;
    return DATA_DIR + "board/" + id;
}

string short()
{
    mapping *notes;
    int i, unread, last_read_time;

    notes = query("notes");
    if (!pointerp(notes) || !sizeof(notes))
        return ::short() + " [ 没有任何留言 ]";

    if (this_player())
    {
        last_read_time = (int)this_player()->query("board_last_read/" + (string)query("board_id"));
        for (unread = 0, i = sizeof(notes) - 1; i >= 0; i--, unread++)
            if (notes[i]["time"] <= last_read_time)
                break;
    }
    if (unread)
        return sprintf(HIC + "%s" + NOR + " [ %d 张留言，" + HIY + "%d" + NOR + " 张" +
                       HIR + "未读" + NOR + "]", ::short(), sizeof(notes), unread);
    else
        return sprintf("%s [ %d 张留言 ]", ::short(), sizeof(notes));
}

string long()
{
    mapping *notes;
    int i, last_time_read;
    string msg /*, myid*/;
    object where;

    where = environment(this_player());

    if ((string)file_name(where) == "/d/wizard/noname_room" && !wizardp(this_player()))
        return "该留言版只有巫师才能查阅。\n";

    notes = query("notes");
    msg = query("long");
    msg = msg + "留言版的使用方法请见 help board。\n";
    if (!pointerp(notes) || !sizeof(notes))
        return query("long");

    last_time_read = this_player()->query("board_last_read/" + (string)query("board_id"));
    i = sizeof(notes) - 50;
    if (i < 0)
        i = 0;
    for (; i < sizeof(notes); i++)
        msg += sprintf("%s[%2d]" NOR "  %-40s %12s (%s)\n",
                       (notes[i]["time"] > last_time_read ? HIY : ""),
                       i + 1, notes[i]["title"], notes[i]["author"], ctime(notes[i]["time"])[0..15]);
    return msg;
}

// This is the callback function to process the string returned from the
// editor defined in F_EDIT of player object.
void done_post(object me, mapping note, int n, string text)
{
    int i;
    int pl;
    string sign;
    string pure;
    mapping *notes;

    if (!n)
        n = me->query("env/default_sign");
    if (!stringp(sign = me->query(sprintf("env/sign%d", n))))
    {
        // auto select the first none null sign
        for (i = 1; i <= 4; i++)
        {
            sign = me->query(sprintf("env/sign%d", i));
            if (stringp(sign))
                break;
        }
    }

    if (stringp(sign))
    {
        sign = replace_string(sign, "\\n", "\n");
        sign = trans_color(sign, 1);
        pure = filter_color(sign);
        if (strlen(pure) >= 1 && pure[strlen(pure) - 1] != '\n')
            sign += "\n";

        pure = filter_color(text);
        pl = strlen(pure);
        if (pl >= 1 && pure[pl - 1] != '\n')
            text += "\n\n" + sign;
        else if (pl >= 2 && pure[pl - 2] != '\n')
            text += "\n" + sign;
        else
            text += sign;
    }

    note["msg"] = text;
    notes = query("notes");
    if (!pointerp(notes) || !sizeof(notes))
        notes = ({note});
    else
    {
        i = sizeof(notes) - 1;
        if (note["time"] <= notes[i]["time"])
            note["time"] = notes[i]["time"] + 1;
        notes += ({note});
    }

    // Truncate the notes if maximum capacity exceeded.
    if (sizeof(notes) > BOARD_CAPACITY)
        notes = notes[BOARD_CAPACITY / 2..BOARD_CAPACITY];

    set("notes", notes);
    tell_object(me, "留言完毕。\n");

    save();
    return;
}

int do_post(string arg, int n)
{
    mapping note;
    if (!arg)
        return notify_fail("留言请指定一个标题。\n");

    if (sscanf(arg, "%s with %d", arg, n) != 2)
        n = 0;

    if (replace_string(arg, " ", "") == "")
        arg = "无标题";

    note = allocate_mapping(4);
    note["title"] = arg;
    note["author"] = this_player()->query("name") + "-" + this_player()->query("id");
    note["time"] = time();
    this_player()->edit((
        : done_post, this_player(), note, n:));
    return 1;
}

int do_read(string arg)
{
    int num;
    mapping *notes, last_read_time;
    string myid;
    object where;

    where = environment(this_player());

    if ((string)file_name(where) == "/d/wizard/noname_room" && !wizardp(this_player()))
        return notify_fail("该留言版只有巫师才能查阅。\n");

    last_read_time = this_player()->query("board_last_read");
    myid = query("board_id");
    notes = query("notes");

    if (!pointerp(notes) || !sizeof(notes))
        return notify_fail("留言板上目前没有任何留言。\n");

    if (!arg)
        return notify_fail("指令格式：read <留言编号>|new|next\n");
    if (arg == "new" || arg == "next")
    {
        if (!mapp(last_read_time) || undefinedp(last_read_time[myid]))
            num = 1;
        else
            for (num = 1; num <= sizeof(notes); num++)
                if (notes[num - 1]["time"] > last_read_time[myid])
                    break;
    }
    else if (!sscanf(arg, "%d", num))
        return notify_fail("你要读第几张留言？\n");

    if (num < 1 || num > sizeof(notes))
        return notify_fail("没有这张留言。\n");
    num--;
    this_player()->start_more(sprintf(
            "[%d] %-40s %s(%s)\n----------------------------------------------------------------------\n",
            num + 1, notes[num]["title"], notes[num]["author"], ctime(notes[num]["time"])[0..9]) +
            notes[num]["msg"]);

    // Keep track which post we were reading last time.
    if (!mapp(last_read_time))
        this_player()->set("board_last_read", ([myid:notes[num]["time"]]));
    else if (undefinedp(last_read_time[myid]) || notes[num]["time"] > last_read_time[myid])
        last_read_time[myid] = notes[num]["time"];

    return 1;
}

int do_discard(string arg)
{
    mapping *notes;
    int num;

    if (!arg || sscanf(arg, "%d", num) != 1)
        return notify_fail("指令格式：discard <留言编号>\n");
    notes = query("notes");
    if (!arrayp(notes) || num < 1 || num > sizeof(notes))
        return notify_fail("没有这张留言。\n");
    num--;
    if (notes[num]["author"] != (string)this_player()->query("name") + "-" + this_player()->query("id") &&
        (string)SECURITY_D->get_status(this_player()) != "(admin)" && (string)SECURITY_D->get_status(this_player()) != "(arch)")
        return notify_fail("这个留言不是你写的。\n");

    notes = notes[0..num - 1] + notes[num + 1..sizeof(notes)-1];
    set("notes", notes);
    save();
    write("删除第 " + (num + 1) + " 号留言....Ok。\n");
    return 1;
}
